package com.xiyuan.smartutils.client.http;

import com.xiyuan.smartutils.Bytes;
import com.xiyuan.smartutils.StrUtils;
import com.xiyuan.smartutils.Validates;
import com.xiyuan.smartutils.client.domain.FileItem;
import com.xiyuan.smartutils.client.domain.FormData;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * HTTP/HTTPS POST访问类
 * 1.内容以字符串为主，在写入时根据编码格式转换成字节
 * 2.当内容不为空时，必须有mimeType和encoding值
 * 默认 UTF8 编码
 *
 * @version v1.0.0 @author lgz 2017-9-21 新建与整理
 */
public class HttpPost extends HttpClient {
    private String queryString;
    private String mimeType;
    private String encoding;
    
    private FormData formData;
    
    
    public HttpPost(String url) {
        super(url, _POST_);
        this.mimeType = _APPLICATION_X_WWW_FORM_;
        this.encoding = _UTF_8_;
        this.formData = new FormData(this.encoding);
        
    }
    
    public HttpPost setQueryString(String queryString) {
        this.queryString = StrUtils.trim(queryString);
        return this;
    }
    
    
    public HttpPost setQueryString(String queryString, String encoding) {
        this.queryString = StrUtils.trim(queryString);
        this.encoding = StrUtils.trim(encoding);
        return this;
    }
    
    public HttpPost setQueryString(String queryString, String mimeType, String encoding) {
        this.queryString = StrUtils.trim(queryString);
        this.mimeType = StrUtils.trim(mimeType);
        this.encoding = StrUtils.trim(encoding);
        return this;
    }
    
    private FormData initForm(FormData form) {
        if (this.formData == null) {
            this.formData = form != null ? form : new FormData();
        }
        this.encoding = formData.getEncoding();
        this.mimeType = formData.getContentType();
        return this.formData;
    }
    
    private FormData initForm() {
        return initForm(null);
    }
    
    public HttpPost setFormData(FormData formData) {
        this.queryString = null;
        this.initForm(formData);
        return this;
    }
    
    /**
     * 添加参数 添加参数
     *
     * @param name 参数名
     * @param val  参数值
     * @return this formData;
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    private HttpPost addParam(String name, Object val) throws IllegalArgumentException {
        
        return addParam(name, (val == null ? null : String.valueOf(val)));
    }
    
    /**
     * 添加参数 添加参数
     *
     * @param name 参数名
     * @param val  参数值
     * @return this formData;
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    public HttpPost addParam(String name, String val) throws IllegalArgumentException {
        initForm().append(name, val);
        return this;
    }
    
    public HttpPost setParamMap(Map<String, String> paramMap) throws IllegalArgumentException {
        initForm().setParamMap(paramMap);
        return this;
    }
    
    /**
     * 添加参数
     *
     * @param name 参数名
     * @param val  参数值
     * @return this formData;
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    public HttpPost addParam(String name, Boolean val) throws IllegalArgumentException {
        this.addParam(name, (Object) val);
        return this;
    }
    
    /**
     * 添加参数
     *
     * @param name 参数名
     * @param val  参数值
     * @return this formData;
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    public HttpPost addParam(String name, Integer val) throws IllegalArgumentException {
        return this.addParam(name, (Object) val);
    }
    
    /**
     * 添加参数
     *
     * @param name 参数名
     * @param val  参数值
     * @return this formData;
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    public HttpPost addParam(String name, Long val) throws IllegalArgumentException {
        return this.addParam(name, (Object) val);
    }
    
    /**
     * 添加参数
     *
     * @param name 参数名
     * @param val  参数值
     * @return this formData;
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    public HttpPost addParam(String name, Double val) throws IllegalArgumentException {
        return this.addParam(name, (Object) val);
    }
    
    public HttpPost addParam(String name, Float val) throws IllegalArgumentException {
        return this.addParam(name, (Object) val);
    }
    
    public HttpPost addParam(String name, Byte val) throws IllegalArgumentException {
        return this.addParam(name, (Object) val);
    }
    
    public HttpPost addParam(String name, Short val) throws IllegalArgumentException {
        return this.addParam(name, (Object) val);
    }
    
    public HttpPost addParam(String name, Character val) throws IllegalArgumentException {
        return this.addParam(name, (Object) val);
    }
    
    public HttpPost addParam(String name, AtomicBoolean val) throws IllegalArgumentException {
        return this.addParam(name, val == null ? null : val.get());
    }
    
    public HttpPost addParam(String name, AtomicInteger val) throws IllegalArgumentException {
        return this.addParam(name, val == null ? null : val.get());
    }
    
    public HttpPost addParam(String name, AtomicLong val) throws IllegalArgumentException {
        return this.addParam(name, val == null ? null : val.get());
    }
    
    /**
     * 添加参数
     *
     * @param name 参数名
     * @param val  参数值
     * @return this instalce
     */
    public HttpPost addParam(String name, Number val) throws IllegalArgumentException {
        return this.addParam(name, (Object) val);
    }
    
    
    /**
     * 添加文件参数
     *
     * @param name     参数名
     * @param fileItem 文件参数
     * @return this instalce
     */
    public HttpPost addFile(String name, FileItem fileItem) {
        initForm().appendFile(name, fileItem);
        return this;
    }
    
    /**
     * 添加文件参数
     *
     * @param name     参数名
     * @param fileName 文件名
     * @param file     文件对象
     * @return this instalce
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    public HttpPost addFile(String name, String fileName, File file) {
        initForm().appendFile(name, fileName, file);
        return this;
    }
    
    /**
     * 添加文件参数
     *
     * @param name 参数名
     * @param file 文件对象
     * @return this instalce
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    public HttpPost addFile(String name, File file) {
        initForm().appendFile(name, file);
        return this;
    }
    
    /**
     * 添加文件参数
     *
     * @param name        参数名
     * @param fileName    文件名
     * @param mimeType    文件mimeType
     * @param fileContent 文件类型
     * @return this instalce
     * @throws IllegalArgumentException throw IllegalArgumentException when name is empty or blank;
     */
    public HttpPost addFile(String name, String fileName, byte[] fileContent, String mimeType) throws
                                                                                               IllegalArgumentException {
        initForm().appendFile(name, fileName, fileContent, mimeType);
        return this;
    }
    
    /**
     * 移除参数
     *
     * @param name 参数名
     * @return this instance
     */
    public HttpPost removeParameter(String name) {
        initForm().remove(name);
        return this;
    }
    
    /**
     * 移除文件参数
     *
     * @param name 参数名
     * @return this instance
     */
    public HttpPost removeFile(String name) {
        initForm().remove(name);
        return this;
    }
    
    @Override
    protected boolean doPreRequestProperty() throws IOException {
        
        String contentType = getRequestHeader(_CONTENT_TYPE_);
        
        if (Validates.isBlank(contentType)) {
            contentType = mimeType;
            removeRequestHeader(_CONTENT_TYPE_);
        }
        
        if (!contentType.contains("charset")) {
            contentType += "; charset=" + encoding;
        }
        
        long contentLength = 0;
        if (queryString != null) {
            contentLength = Bytes.getByteLen(queryString, encoding);
        }
        else if (formData != null) {
            contentLength = formData.getContentLength();
            contentType = formData.getContentType();
        }
        
        setDoOutput(true);
        if (!hasRequestHeader(_CONTENT_TYPE_)) {
            // 外部没有设置请求头时
            addRequestProperty(_CONTENT_TYPE_, contentType);
        }
        addRequestProperty(_CONTENT_LENGTH_, contentLength);
        return true;
    }
    
    
    @Override
    protected void doWriteContent(HttpURLConnection conn) throws IOException {
        OutputStream out = conn.getOutputStream();
        if (queryString != null) {
            out.write(queryString.getBytes(encoding));
        }
        else if (formData != null) {
            formData.write(out);
        }
    }
    
    public String getQueryString() {
        return queryString != null ? queryString : (formData != null ? formData.createFormBody() : "");
    }
}
